﻿// Inner Fire 游戏引擎库
// ObjectFactory - 游戏对象工厂
//
// Copyright (c) 2025 by 尔西大帝. All rights reserved.
//
// 所属层级：应用层（4）
// 用于创建各种不同类型的游戏对象
//
// Author: 尔西大帝
// Email: 2670613871@qq.com
// Created: 2025-03-12

#pragma once

#include <dx/graphics/dx_graphics.h>
#include <game/object/camera_object.h>
#include <game/object/instanced_sprite_object.h>
#include <game/object/map_object.h>
#include <game/object/skin_mesh_object.h>
#include <game/object/standard_object.h>
#include <game/config/prefab.h>

namespace ifire::game {
class GameManager;
class Assets;
class ResourceManager;
class Material;

struct ModelLoader {
  ikit::sstr name;
  Model* model;

  ModelLoader(ikit::sstr _name) : name(_name), model(nullptr) {}
};

class ObjectFactory {
public:
  ObjectFactory(Scene* scene, GameManager* gm);
  ObjectFactory(const ObjectFactory& lhs) = delete;
  ObjectFactory& operator=(const ObjectFactory& lhs) = delete;
  ~ObjectFactory() = default;

  // 初始化创建环境
  void SetupEnvironment();

  // 对项目进行循环
  void FixedUpdate();
  // 对项目进行延时循环
  void LateUpdate();

  // 创建一个相机对象
  CameraObject* CreateCamera(ikit::sstr name_id, ikit::sstr prefab_name);
  // 创建一个实例精灵对象
  InstancedSpriteObject* CreateInstancedSprite(ikit::sstr name_id,
      ikit::sstr type_name, ikit::sstr model_name, size_t count);
  // 创建一个简单对象，只有一个Mesh
  GameObject* CreateSingleObject(const Prefab& info);
  // 创建一个简单对象，只有一个Mesh（使用Prefab名称的快捷方式）
  GameObject* CreateSingleObject(ikit::sstr prefab_name);
  // 创建一个标准对象
  GameObject* CreateStandardObject(Model* model, const Prefab& info);
  // 创建一个骨骼动画对象
  GameObject* CreateSkinMeshObject(Model* model, const Prefab& info);
  // 创建一个地图对象
  MapObject* CreateMapObject(ikit::sstr prefab_name);
  // 检查是否通过项目，如果不通过，则会中断Command，进行提交，不然会出问题。
  bool CheckValidated(void* model, const Prefab* prefab);
  // 载入一个Model
  Model* LoadModel(ikit::sstr model_name);
  // 载入一批Model
  void LoadModels(eastl::vector<ModelLoader>& models);
  // 将一个Model加入项目，如果已经存在，则不加入
  void AddTo(eastl::vector<ModelLoader>& models, ikit::sstr name);
  // 从队列中选择出一个Model
  Model* GetModel(const eastl::vector<ModelLoader>& models, ikit::sstr name);
  // 获取一个Model中的Materal
  Material* PickMaterial(const Prefab* info, Model* model, int material_index);
  // 根据Prefab创建一个SubMesh，并执行通用的设置
  dx::RenderItem* CreateAndSetRenderItem(
      const Prefab& info, Model* model, const dx::DxSubmesh& sub);

  // 查找一个对象
  GameObject* FindObject(ikit::sstr name);
  // 创建一个对象，使用prefab创建
  GameObject* CreateObject(ikit::sstr prefab_name);

  //
  // 属性访问
  //
  const eastl::vector<GameObjectPtr>& Objects() const { return objects_; }

private:
  // 增加到Object，返回指针
  template <typename T> auto CreateObjectPtr(const Prefab& info) {
    auto obj = std::make_unique<T>(info.name, scene_, nullptr);
    auto ptr = obj.get();
    objects_.push_back(std::move(obj));
    return ptr;
  }

  Scene* scene_;
  GameManager* gm_;
  dx::DxGraphics* dx_;
  Assets* assets_;
  ConfigManager* config_;
  ResourceManager* resources_;

  eastl::vector<GameObjectPtr> objects_;
};
} // namespace ifire::game